Image Features

This notebook provides a guide on how to extract features from an image. The features that are currently implemented are:

  1. HOG
  2. IGO
  3. ES
  4. LBP

It also shows in Section 5 that features can be combined.

Firstly, let's import the needed packages


In [ ]:
import menpo.io as pio

and load and plot an input image


In [ ]:
%matplotlib inline
breaking_bad = pio.import_builtin_asset('breakingbad.jpg')
breaking_bad.crop_to_landmarks(boundary=20)
breaking_bad.constrain_mask_to_landmarks()
breaking_bad.view(masked=False)
print breaking_bad.mask

The input image is annotated


In [ ]:
breaking_bad.landmarks.view()

and has 3 channels (RGB)


In [ ]:
breaking_bad.view(channels='all')

1. HOG Features

The HOG (Histogram of Oriented Gradients) features method clusters gradient orientations in different bins for localized sub-windows of the input image, resulting in counting occurences of the orientations. One can extract dense HOGs with control over the density and sparse which refer to the original HOGs formulation.

1.1 Dense HOGs

This is an example of dense HOGs with sampling step of 3 pixels horizontally and vertically. In this example, we include all the possible HOG parameters.


In [ ]:
%%time
hog = breaking_bad.features.hog(mode='dense',
                                algorithm='dalaltriggs',
                                cell_size=8,
                                block_size=2,
                                num_bins=9,
                                signed_gradient=True,
                                l2_norm_clip=0.2,
                                window_height=1, window_width=1, window_unit='blocks',
                                window_step_vertical=3, window_step_horizontal=3, window_step_unit='pixels',
                                padding=True,
                                verbose=True,
                                constrain_landmarks=True)

Visualize with and without landmarks and either in glyph or image mode:


In [ ]:
hog.view(masked=False)

In [ ]:
hog.glyph().landmarks.view()

I prefer this visualization technique


In [ ]:
hog.glyph(vectors_block_size=1,).landmarks.view(channels='all')

1.2 Sparse HOGs

Setting the mode option to sparse returns the original sparsely-sampled HOGs


In [ ]:
%%time
hog = breaking_bad.features.hog(mode='sparse',
                                algorithm='zhuramanan',
                                verbose=True)
hog.glyph(vectors_block_size=4).view()

and with landmarks:


In [ ]:
hog.landmarks.view(masked=False)

1.3 Default Options

The extraction of HOG features with the default options


In [ ]:
%%time
hog = breaking_bad.features.hog()

returns the most densely-sampled HOG version and is of course very slow...


In [ ]:
print hog

They return a HOG image with the same width and height as the input image.


In [ ]:
hog.view(channels=range(9))

In [ ]:
hog.glyph(vectors_block_size=1).landmarks.view(channels='all')

1.4 Constrain Landmarks

In some cases, depending on the options given by the user, the landmarks may end up outside of the bounds of the features image. By enabling the flag _constrainlandmarks, the landmarks that lie outside the borders will be constrained to the image bounds. The default value is constrain_landmarks=True. This applies in all features categories. For example:


In [ ]:
# clipping disabled
subplot(121); title('Clipping disabled')
breaking_bad.resize([150, 150]).features.hog(mode='sparse',constrain_landmarks=False).landmarks.view(channels=1,masked=False)
# clipping enabled
subplot(122); title('Clipping enabled')
breaking_bad.resize([150, 150]).features.hog(mode='sparse').landmarks.view(channels=1,masked=False)

1.5 Windows Centres

All feature types return a matrix with the coordinates of the windows centers on which they were computed:


In [ ]:
hog = breaking_bad.features.hog(mode='sparse')
print hog.pixels.shape
print hog.window_centres.shape

2. IGO Features

The IGO (Image Gradient Orientations) features concatenate the cos() and sin() of the gradient orientation angles at each image pixel. The cos() and sin() can be computed either on the actual orientation angles or to both the initial and double value of the angles.

2.1 Single angles

Here is an example of such computation, which is set to be the default:


In [ ]:
%%time
igo_single = breaking_bad.features.igo()

In [ ]:
print igo_single

In [ ]:
igo_single.view(channels='all')

or


In [ ]:
igo_single.glyph().view(channels='all')

2.2 Double angles

This is an example by enabling the double_angles flag. This is the only parameter that is related to the IGO computation.


In [ ]:
%%time
igo = breaking_bad.features.igo(double_angles=True, verbose=True)

In [ ]:
igo.view(channels='all')

In [ ]:
igo.glyph(vectors_block_size=1).landmarks.view(channels='all')

3. ES Features

ES (Edge Structure) features provide a measure which captures the orientation of image structure at each pixel, together with an indication of how accurate the orientation estimate is. The accuracy belief measure penalizes the orientations in flat, noisy regions and favours the ones near strong edges. Here is an example:


In [ ]:
%%time
es = breaking_bad.features.es(verbose=True)

In [ ]:
es.view(channels=[0, 1])

In [ ]:
es.glyph(vectors_block_size=1).landmarks.view(channels='all')

4. LBP Features

The basic idea behind LBP (Local Binary Patterns) features is to encode the local structure in an image by comparing each pixel’s intensity value with its neighborhood and then assign an appropriate code. The user can control their density through the window_step_vertical and window_step_horizontal parameters. At each pixel, the LBP code is computed on circle(s) with radius (radii) defined in radius. For each radius value, the user has to define the respective number of sampling points, using the parameter samples. The parameter mapping_type defines the LBP codes mapping: uniform-2, rotation-invariant or _uniform-2 and rotationinvariant.

In this example, we extract quite dense LBP features using two radius/samples combinations. The example also includes all the possible parameters.


In [ ]:
%%time
lbp = breaking_bad.features.lbp(radius=[3, 4],
                                samples=[10, 12],
                                mapping_type='ri',
                                window_step_vertical=1,
                                window_step_horizontal=1,
                                window_step_unit='pixels',
                                padding=True,
                                verbose=True,
                                constrain_landmarks=True)

In [ ]:
lbp.view(channels='all')

Here is an example with the default values:


In [ ]:
%%time
lbp = breaking_bad.features.lbp()

In [ ]:
lbp.glyph(vectors_block_size=1).landmarks.view(channels='all')

Note that all implemented features hold the parameters' values given by the user:


In [ ]:
print lbp.lbp_parameters

4.1 LBP Codes Histogram

LBPs are ideal to be used as image descriptors. This is achieved by binning the codes of the output image, as follows:


In [ ]:
hist, bin_edges = breaking_bad.as_greyscale().features.lbp(radius=1, samples=8).as_histogram()

In [ ]:
width = 0.7 * (bin_edges[1] - bin_edges[0])
center = (bin_edges[:-1] + bin_edges[1:]) / 2
plt.bar(center, hist, align='center', width=width)

5. Features Combination

The user is able to extract features from a features image (if that makes any sense!). For example we can compute the LBP features of the IGO-based image:


In [ ]:
%%time
lbp_igo = breaking_bad.as_greyscale().features.igo(verbose=True).features.lbp(radius=2, samples=8, mapping_type='none', verbose=True)

In [ ]:
lbp_igo.landmarks.view(channels='all')